/*
 * Copyright Hundsun Technologies Inc. All Rights Reserved.
 */

package main

import (
	"flag"
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"runtime"
	"runtime/debug"
	"strconv"
	"syscall"
	"time"

	"hundsun.com/hsl/hschain/common/config"
	"hundsun.com/hsl/hschain/common/log"
	"hundsun.com/hsl/hschain/common/log/logging"
	"hundsun.com/hsl/hschain/common/util/pb"
	"hundsun.com/hsl/hschain/common/version"
	_ "hundsun.com/hsl/hschain/consensus/init"
	_ "hundsun.com/hsl/hschain/contract/init"
	module "hundsun.com/hsl/hschain/module/impl"
	_ "hundsun.com/hsl/hschain/p2p/init"
	"hundsun.com/hsl/hschain/store"
	_ "hundsun.com/hsl/hschain/store/init"
)

const (
	configKeyPprofEnabled = "pprof.enabled"
	configKeyPprofPort    = "pprof.port"
	configGcEnable        = "gc.enable"
	configGcPercent       = "gc.percent"
)

var (
	versionCmd = flag.Bool("v", false, "version")
)

func main() {
	flag.Parse()
	if *versionCmd {
		fmt.Println("hschain version", version.GetVersion())
		return
	}
	// Initialize config
	config.Initialize("")
	// Initialize log
	log.Initialize()
	// Initialize store
	store.Initialize()
	// load genesis block
	_ = pb.GetGenesisBlock()

	logger := log.WithField(logging.LogFieldMain, logging.LogFieldMain)
	logger.Info("hschain startup ...")
	mgtService := module.GetMgtServiceInstance()

	// init
	if err := mgtService.Init(); err != nil {
		logger.Info("failed to startup hschain")
		return
	}

	// keep alive
	//mgtService.RefreshModulesLockerTtl()
	//mgtService.RefreshModulesRegCenterTtl()
	logger.Info("success to startup hschain")

	// clean
	defer func() {
		// close all modules and clean
		logger.Info("hschain exiting ...")
		mgtService.Close()
	}()

	// pprof
	go func() {
		pprofEnabled := config.GetBoolConfigValue(configKeyPprofEnabled, false)
		if pprofEnabled {
			pprofPort := config.GetIntConfigValue(configKeyPprofPort, 6060)
			if pprofPort == 0 {
				pprofPort = 6060
			}
			logger.Infof("pprof enabled,port: %d", pprofPort)
			err := http.ListenAndServe("0.0.0.0:"+strconv.Itoa(pprofPort), nil)
			if err != nil {
				logger.Fatal(err)
			}
		}
	}()

	// gc
	go func() {
		gcEnable := config.GetBoolConfigValue(configGcEnable, true)
		if gcEnable {
			gcPercent := config.GetIntConfigValue(configGcPercent, 30)
			logger.Infof("gc enabled, percent: %d", gcPercent)
			debug.SetGCPercent(gcPercent)
		}
	}()

	// mem stats watching
	t := time.Tick(30 * time.Second)
	go func() {
		for range t {
			watching()
		}
	}()

	// 阻塞main
	Wait(logger)
}

//Wait ...
func Wait(logger logging.Log) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	// Block until a signal is received.
	s := <-c
	logger.Info("Got signal:", s)
}

func watching() {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)
	log.Info("info:", "NumGoroutine:", runtime.NumGoroutine())
	log.Info("info:", "Mem:", m.Sys/(1024*1024))
	log.Info("info:", "HeapAlloc:", m.HeapAlloc/(1024*1024))
}
